package com.baofu.paycore.manager.storer.impl;

import com.alibaba.fastjson.JSONObject;
import com.baofu.paycore.common.exception.PayCoreBizException;
import com.baofu.paycore.dal.mapper.ClearAccountMapper;
import com.baofu.paycore.dal.mapper.ClearBankMapper;
import com.baofu.paycore.dal.mapper.ClearMapper;
import com.baofu.paycore.dal.mapper.FreezeMapper;
import com.baofu.paycore.dal.model.ClearAccountDO;
import com.baofu.paycore.dal.model.ClearBankDO;
import com.baofu.paycore.dal.model.ClearDO;
import com.baofu.paycore.dal.model.FreezeDO;
import com.baofu.paycore.dal.model.base.BaseDO;
import com.baofu.paycore.manager.converter.BO2DOConverter;
import com.baofu.paycore.manager.converter.DO2BOConverter;
import com.baofu.paycore.manager.model.withdraw.WithdrawBO;
import com.baofu.paycore.manager.model.withdraw.WithdrawBankBO;
import com.baofu.paycore.manager.model.withdraw.WithdrawFundBO;
import com.baofu.paycore.manager.storage.impl.ClearAccountManager;
import com.baofu.paycore.manager.storage.impl.ClearBankManager;
import com.baofu.paycore.manager.storage.impl.ClearManager;
import com.baofu.paycore.manager.storer.AbstractOrderRepository;
import com.baofu.paycore.manager.storer.WithdrawOrderRepository;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.enums.ServiceCodeEnum;
import com.google.common.collect.Lists;
import com.system.commons.sequence.redis.SequenceFacade;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * 充值单
 *
 * <p>
 *  1.订单转换
 *  2.加载并锁定订单
 *  3.加载订单
 *  4.幂等性校验
 * </p>
 * User: xin deng  Date: 16/6/3 ProjectName: paycore Version: 1.0
 */
@Slf4j
@Component
public class WithdrawOrderRepositoryImpl extends AbstractOrderRepository<WithdrawBO>
        implements WithdrawOrderRepository {

    /**
     * 提现主单mapper
     */
    @Autowired
    private ClearMapper clearMapper;

    /**
     * 提现资金单mapper
     */
    @Autowired
    private ClearAccountMapper clearAccountMapper;

    /**
     * 提现银行单mapper
     */
    @Autowired
    private ClearBankMapper clearBankMapper;

    /**
     * sequence生成类
     */
    @Autowired
    private SequenceFacade sequenceFacade;

    /**
     *资金单处理manager
     */
    @Autowired
    private ClearAccountManager clearAccountManager;

    /**
     * 充值/提现银行资金单
     */
    @Autowired
    private ClearBankManager clearBankManager;

    /**
     * 主订单
     */
    @Autowired
    private ClearManager clearManager;

    /**
     * 冻结单
     */
    @Autowired
    private FreezeMapper freezeMapper;

    /**
     * 订单转换
     *
     * @param withdrawBO   支付对象
     * @return             转换后DO
     */
    @Override
    protected List<BaseDO> convertToDO(WithdrawBO withdrawBO) {

        List<BaseDO> list = Lists.newArrayList();
        //提现主单
        list.add(BO2DOConverter.getWithdrawClearDO(withdrawBO));
        //冻结单
        FreezeDO freezeDO = BO2DOConverter.getFreezeDO(withdrawBO);
        if (freezeDO != null) {
            list.add(freezeDO);
        }
        //提现银行单
        list.add(BO2DOConverter.getClearBankDO(withdrawBO));
        //提现资金单
        list.addAll(BO2DOConverter.getClearAccountList(withdrawBO.getWithdrawFundBO(), withdrawBO.getOperator()));

        return list;
    }

    /**
     * 加载并锁定订单
     *
     * @param requestOrderNo   请求订单号
     * @param requestBizNo     请求流水号
     * @return                 支付信息
     */
    @Override
    public WithdrawBO lock(String requestOrderNo, String requestBizNo,String requestSystem) {
        return null;
    }

    /**
     * 加载订单
     *
     * @param requestOrderNo    请求订单号
     * @return                  订单
     */
    @Override
    public WithdrawBO load(String requestOrderNo) {
        //充值资金单
        ClearBankDO clearBankDO = clearBankMapper.queryClearBankByPayNo(requestOrderNo);
        if (clearBankDO == null) {
            log.error("查询充值资金单信息为空 fundDetailNo:{}", requestOrderNo);
            throw new PayCoreBizException(PayCoreErrorCode.ORDER_IS_NOT_EXISTED);
        }
        //主单
        ClearDO clearDO = clearMapper.queryClearByPayNo(clearBankDO.getPayNo());

        //冻结单
        FreezeDO freezeDO = freezeMapper.selectByPayNo(clearBankDO.getPayNo());
        //充值资金单
        List<ClearAccountDO> clearAccountDO = clearAccountMapper.queryClearAccountByPayNo(clearBankDO.getPayNo());

        return buildWithdrawBO(clearDO,freezeDO, clearAccountDO, clearBankDO);
    }

    /**
     * 幂等性校验
     *
     * @param requestBizNo     请求流水号
     * @param requestOrderNo   请求订单号
     * @return                 订单
     */
    @Override
    public WithdrawBO checkIdempotent(String requestBizNo, String requestOrderNo,String requestSystem) {
        ClearDO clearDO = clearMapper.queryByOrderNo(requestOrderNo,requestBizNo,null,requestSystem);
        return DO2BOConverter.getWithdrawBO(clearDO);
    }

    /**
     * 封装提现单信息
     *
     * @param clearDO           充值主单信息
     * @param clearAccountDO    充值资金单信息
     * @param clearBankDO       充值银行单信息
     * @return                  充值单信息
     */
    private WithdrawBO buildWithdrawBO(ClearDO clearDO,FreezeDO freezeDO, List<ClearAccountDO> clearAccountDO, ClearBankDO clearBankDO) {

        WithdrawBO withdrawBO = new WithdrawBO();
        withdrawBO.setPayNo(clearDO.getPayNo());
        withdrawBO.setAccountNo(clearDO.getAccountNo());
        withdrawBO.setBizType(clearDO.getBizType());
        withdrawBO.setSubBizType(clearDO.getSubBizType());
        withdrawBO.setContractNo(clearDO.getContractNo());
        withdrawBO.setPaymentExt(JSONObject.parseObject(clearDO.getDepositExtra(), Map.class));
        withdrawBO.setRequestSystem(clearDO.getRequestSystem());
        withdrawBO.setRequestOrderNo(clearDO.getRequestOrderNo());
        withdrawBO.setRequestBizNo(clearDO.getRequestBizNo());
        withdrawBO.setRelationNo(clearDO.getRelationNo());
        withdrawBO.setServiceCode(clearDO.getServiceCode());
        withdrawBO.setMerchantNo(clearDO.getMerchantNo());
        withdrawBO.setPaymentInfo(clearDO.getPaymentInfo());
        withdrawBO.setStatus(clearDO.getStatus());
        withdrawBO.setOperator(clearDO.getCreatedBy());
        withdrawBO.setCcy(clearDO.getCcy());
        withdrawBO.setAmt(clearDO.getAmt());
        //提现资金单
        List<WithdrawFundBO> withdrawFundBOs = DO2BOConverter.getWithdrawFundBOList(clearAccountDO);
        //提现冻结单
        if(freezeDO!=null){
            withdrawFundBOs.add(DO2BOConverter.getFreezeFundBO(freezeDO));
        }
        //提现银行单
        WithdrawBankBO withdrawBankBO = DO2BOConverter.getWithdrawBankBO(clearBankDO);
        withdrawBO.setWithdrawFundBO(withdrawFundBOs);

        withdrawBO.setWithdrawBankBO(withdrawBankBO);
        return withdrawBO;
    }

    /**
     * 依payNo加载订单
     *
     * @param payNo 支付单号
     * @return 提现单
     */
    @Override
    public WithdrawBO loadOrderByPayNo(String payNo) {
        //银行单
        ClearBankDO clearBankDO = clearBankMapper.queryClearBankInfo(payNo);
        if (clearBankDO == null) {
            log.error("查询银行单信息为空 payNo:{}", payNo);
            throw new PayCoreBizException(PayCoreErrorCode.ORDER_IS_NOT_EXISTED);
        }
        //主单
        ClearDO clearDO = clearMapper.queryClearByPayNo(clearBankDO.getPayNo());

        //冻结单
        FreezeDO freezeDO=freezeMapper.selectByPayNo(clearBankDO.getPayNo());

        //充值资金单
        List<ClearAccountDO> clearAccountDO = clearAccountMapper.queryClearAccountByPayNo(clearBankDO.getPayNo());

        return buildWithdrawBO(clearDO,freezeDO, clearAccountDO, clearBankDO);
    }

    @Transactional(isolation = Isolation.DEFAULT,
            propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public void addRetryOrder(WithdrawFundBO withdrawFundBO,String operator) {
        ClearAccountDO clearAccountDO=BO2DOConverter.getClearAccountDO(withdrawFundBO,
                operator);
        clearAccountDO.setDescription("discard");
        clearAccountMapper.updateDiscard(clearAccountDO);
        clearAccountDO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        clearAccountDO.setStatus(PayStatusEnums.INIT.getCode());
        clearAccountDO.setDescription(null);
        clearAccountDO.setErrorCode(null);
        clearAccountDO.setErrorReason(null);
        clearAccountDO.setUnfreezeNo(sequenceFacade.getUniqueSeq());
        withdrawFundBO.setFundDetailNo(clearAccountDO.getFundDetailNo());
        withdrawFundBO.setUnfreezeNo(clearAccountDO.getUnfreezeNo());
        clearAccountManager.addOrder(clearAccountDO);
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT,
            propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addUnfreezeWithdrawOrder(WithdrawBO withdrawBO) {
        //提现主单
       ClearDO clearDO=BO2DOConverter.getWithdrawClearDO(withdrawBO);
       clearManager.addOrder(clearDO);
        if(ServiceCodeEnum.ISSUE_WITHDRAW.getCode().equals(withdrawBO.getServiceCode())){
            ClearBankDO clearBankDO=BO2DOConverter.getClearBankDO(withdrawBO);
            clearBankManager.addOrder(clearBankDO);
        }
        List<ClearAccountDO> clearAccountDOS=BO2DOConverter.getClearAccountList(withdrawBO.getWithdrawFundBO(),
                withdrawBO.getOperator());
        for(ClearAccountDO clearAccountDO:clearAccountDOS){
            clearAccountManager.addOrder(clearAccountDO);
        }
    }

    /**
     * 依payNo加载订单
     *
     * @param payNo 支付单号
     * @return 提现单
     */
    public WithdrawBO loadByPayNo(String payNo) {
        //银行单
        ClearBankDO clearBankDO = clearBankMapper.queryClearBankInfo(payNo);
        //主单
        ClearDO clearDO = clearMapper.queryClearByPayNo(payNo);
        //充值资金单
        List<ClearAccountDO> clearAccountDO = clearAccountMapper.queryClearAccountByPayNo(payNo);

        return buildWithdrawBO(clearDO,null, clearAccountDO, clearBankDO);
    }


    @Transactional(isolation = Isolation.DEFAULT,
            propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public void updateRetry(WithdrawBO withdrawBO) {
        //提现主单
        ClearDO clearDO=BO2DOConverter.getWithdrawClearDO(withdrawBO);
        List<ClearAccountDO> clearAccountDOS=BO2DOConverter.getClearAccountList(withdrawBO.getWithdrawFundBO(), withdrawBO.getOperator());
        clearMapper.updateRetry(clearDO);
        clearAccountDOS.forEach(clearAccountDO -> clearAccountMapper.updateDiscard(clearAccountDO));

    }
}
